package com.tmt.datatable.helper;

import com.tmt.helper.DateHelper;
import com.tmt.helper.StringHelper;

import javax.persistence.criteria.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * Created by ThreeManTeam on 2017/6/8.
 */
public class SpecificationHelper {

    /**
     * 获取对应的路径
     *
     * @param root 目标类
     * @param key  阈值
     * @@param parentPath 是否是读取父路径。例如 key='A.B.C', parentPath=true时，仅获取'A.B'路径。
     * @return path
     */
    public static <T> Path path(Root<T> root, String key, boolean parentPath) {
        String[] keys = key.split("\\.");
        int len = parentPath ? Math.max(1, keys.length - 1) : keys.length;
        Path path = null;
        for (int i = 0; i < len; i++) {
            if (i == 0) {
                path = root.get(keys[i]);
            } else {
                if (path != null) {
                    path = path.get(keys[i]);
                }
            }
        }
        return path;
    }

    /**
     * 等于
     */
    public static <T> void eq(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, List<Predicate> predicateList, Class fieldClass, Path path, String[] value) {
        predicateList.add(cb.equal(path, StringHelper.convertTo(value[0], fieldClass)));
    }

    /**
     * 包含
     */
    public static <T> void in(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, List<Predicate> predicateList, Class fieldClass, Path path, String[] value) {
        CriteriaBuilder.In in = cb.in(path);
        List list = new ArrayList();
        Arrays.stream(value).forEach(c -> list.add(StringHelper.convertTo(c, fieldClass)));
        predicateList.add(in.in(list));
    }

    /**
     * 小于或等于
     */
    public static <T> void lte(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, List<Predicate> predicateList, Class<?> fieldClass, Path path, String[] value) {
        Predicate p = null;
        if (fieldClass == Byte.class || fieldClass == byte.class) {
            p = cb.lessThanOrEqualTo(path.as(Byte.class), (Byte) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Short.class || fieldClass == short.class) {
            p = cb.lessThanOrEqualTo(path.as(Short.class), (Short) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Integer.class || fieldClass == int.class) {
            p = cb.lessThanOrEqualTo(path.as(Integer.class), (Integer) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Float.class || fieldClass == float.class) {
            p = cb.lessThanOrEqualTo(path.as(Float.class), (Float) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Double.class || fieldClass == double.class) {
            p = cb.lessThanOrEqualTo(path.as(Double.class), (Double) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Long.class || fieldClass == long.class) {
            p = cb.lessThanOrEqualTo(path.as(Long.class), (Long) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == BigDecimal.class || fieldClass == BigDecimal.class) {
            p = cb.lessThanOrEqualTo(path.as(BigDecimal.class), (BigDecimal) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Date.class || fieldClass == java.sql.Date.class) {
            p = cb.lessThanOrEqualTo(path.as(Date.class), (Date) StringHelper.convertTo(value[0], fieldClass));
        }
        if (p != null) {
            predicateList.add(p);
        }
    }

    /**
     * 大于或等于
     */
    public static <T> void gte(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, List<Predicate> predicateList, Class<?> fieldClass, Path path, String[] value) {
        Predicate p = null;
        if (fieldClass == Byte.class || fieldClass == byte.class) {
            p = cb.greaterThanOrEqualTo(path.as(Byte.class), (Byte) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Short.class || fieldClass == short.class) {
            p = cb.greaterThanOrEqualTo(path.as(Short.class), (Short) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Integer.class || fieldClass == int.class) {
            p = cb.greaterThanOrEqualTo(path.as(Integer.class), (Integer) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Float.class || fieldClass == float.class) {
            p = cb.greaterThanOrEqualTo(path.as(Float.class), (Float) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Double.class || fieldClass == double.class) {
            p = cb.greaterThanOrEqualTo(path.as(Double.class), (Double) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Long.class || fieldClass == long.class) {
            p = cb.greaterThanOrEqualTo(path.as(Long.class), (Long) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == BigDecimal.class) {
            p = cb.greaterThanOrEqualTo(path.as(BigDecimal.class), (BigDecimal) StringHelper.convertTo(value[0], fieldClass));
        }
        if (fieldClass == Date.class || fieldClass == java.sql.Date.class) {
            p = cb.greaterThanOrEqualTo(path.as(Date.class), (Date) StringHelper.convertTo(value[0], fieldClass));
        }
        if (p != null) {
            predicateList.add(p);
        }
    }

    /**
     * 小于或等于
     */
    public static <T> void lteDate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, List<Predicate> predicateList, Class<?> fieldClass, Path path, String[] value) {
        Date date = StringHelper.convertTo(value[0], Date.class);
        Date endOfDate = DateHelper.endOfDate(date);
        predicateList.add(cb.lessThanOrEqualTo(path.as(Date.class), endOfDate));
    }

    public static <T> void between(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, List<Predicate> predicateList, Class<?> fieldClass, Path path, String[] value) {
        Predicate p = null;
        if (fieldClass == Byte.class || fieldClass == byte.class) {
            p = cb.between(path.as(Byte.class), (Byte) StringHelper.convertTo(value[0], fieldClass), (Byte) StringHelper.convertTo(value[1], fieldClass));
        }
        if (fieldClass == Short.class || fieldClass == short.class) {
            p = cb.between(path.as(Short.class), (Short) StringHelper.convertTo(value[0], fieldClass), (Short) StringHelper.convertTo(value[1], fieldClass));
        }
        if (fieldClass == Integer.class || fieldClass == int.class) {
            p = cb.between(path.as(Integer.class), (Integer) StringHelper.convertTo(value[0], fieldClass), (Integer) StringHelper.convertTo(value[1], fieldClass));
        }
        if (fieldClass == Float.class || fieldClass == float.class) {
            p = cb.between(path.as(Float.class), (Float) StringHelper.convertTo(value[0], fieldClass), (Float) StringHelper.convertTo(value[1], fieldClass));
        }
        if (fieldClass == Double.class || fieldClass == double.class) {
            p = cb.between(path.as(Double.class), (Double) StringHelper.convertTo(value[0], fieldClass), (Double) StringHelper.convertTo(value[1], fieldClass));
        }
        if (fieldClass == Long.class || fieldClass == long.class) {
            p = cb.between(path.as(Long.class), (Long) StringHelper.convertTo(value[0], fieldClass), (Long) StringHelper.convertTo(value[1], fieldClass));
        }
        if (fieldClass == BigDecimal.class) {
            p = cb.between(path.as(BigDecimal.class), (BigDecimal) StringHelper.convertTo(value[0], fieldClass), (BigDecimal) StringHelper.convertTo(value[1], fieldClass));
        }
        if (fieldClass == Date.class || fieldClass == java.sql.Date.class) {
            Date start = StringHelper.convertTo(value[0], Date.class);
            Date end = StringHelper.convertTo(value[1], Date.class);
            if (DateHelper.onlyDate(value[1])) {
                end = DateHelper.endOfDate(end);
            }
            p = cb.between(path.as(Date.class), start, end);
        }
        if (p != null) {
            predicateList.add(p);
        }
    }

}
